// RMSListenSocket.cpp: implementation of the CRMSListenSocket class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RMSBaseServer.h"
#include "RMSListenSocket.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CRMSListenSocket::CRMSListenSocket(CBaseServer* base)
{
	pBaseServer = base;
	SERVER_ACTIVE = FALSE;

	m_bPause = FALSE;

	m_hNoClients = NULL;
	PrimaryIP=1;
}

CRMSListenSocket::~CRMSListenSocket()
{
	if(SERVER_ACTIVE)
	{
		StopServer();
		SERVER_ACTIVE = FALSE;
	}
}

DWORD CRMSListenSocket::OnTerminate()
{
	if(m_listenSocket)
	{
		LINGER linger = { 1, 0 };
		//Fixes Bug in MFC Socket Impl
		setsockopt(m_listenSocket, SOL_SOCKET, SO_LINGER, (LPCTSTR)&linger, sizeof(linger));
		shutdown(m_listenSocket, SD_BOTH); 
		closesocket(m_listenSocket);
		m_listenSocket = 0;
	}
	return DEFAULT_TERMINATION_TIMEOUT;
}

DWORD CRMSListenSocket::Terminate(BOOL bCritical)
{
	DWORD result = CRMSThread::Terminate(bCritical);

	list<LPRMSClientSocket>::iterator pClients;

	for(pClients = pBaseServer->m_ListOfClients.begin(); pClients != pBaseServer->m_ListOfClients.end(); pClients++)
	{
		(*pClients)->Terminate();
	}

	if(m_hNoClients)
	{
		DWORD		dwRet;
		dwRet = WaitForSingleObject(m_hNoClients, 5000);
		if (dwRet == WAIT_TIMEOUT)
		{
			TRACE0("One or more client threads did not exit");
		}
		pBaseServer->m_ClientCount.DeleteClientCount();
	}

	return result;
}

DWORD CRMSListenSocket::ThreadFunc()
{
	LPRMSClientSocket pclientSocket;
	SOCKADDR_IN	SockAddr;
	SOCKET		socketClient;
	int			nLen;
	int			camID=0;// we should receive it?

	if (PrimaryIP) {
		pBaseServer->StartCritical();
		m_hNoClients = pBaseServer->m_ClientCount.InitClientCount();
		pBaseServer->EndCritical();
	}

	while(!m_bQuit)
	{
		if(!m_bPause)
		{
			nLen = sizeof(SOCKADDR_IN);
			socketClient = accept(m_listenSocket,
								  (LPSOCKADDR)&SockAddr,
								  &nLen);
			if (socketClient == INVALID_SOCKET)
			{
				break;
			}

			fd_set fdSet;
			FD_ZERO(&fdSet);
			FD_SET(socketClient, &fdSet);
			timeval tv = { 0, 500 };
			int sr = select(1, &fdSet, NULL, NULL, &tv);
			if( sr == 0 || sr == SOCKET_ERROR )
			{
				TRACE1("CRMSListenSocket::ThreadFunc(), select()=%d\n", WSAGetLastError());
			}

			if(m_bQuit) break;
			while(m_bPause)
			{
				if(m_bQuit)
				{
					SERVER_ACTIVE = FALSE;
					m_bTerminated=TRUE;
					return 0;
				}
			}

			pclientSocket = new CRMSClientSocket(pBaseServer);
			TRACE1("%x = new CRMSClientSocket(pBaseServer)\n", pclientSocket);
			TRACE2("  ...inet_ntoa(SockAddr.sin_addr)=%s, inet_ntoa(saServer.sin_addr)=%s\n", inet_ntoa(SockAddr.sin_addr), inet_ntoa(saServer.sin_addr));

			pclientSocket->pBaseServer = pBaseServer;
			pclientSocket->m_clientSocket = socketClient;
			pclientSocket->m_saServer = saServer;
			pclientSocket->m_saClient = SockAddr;

			if((pclientSocket->m_byID = pBaseServer->AddClient(inet_ntoa(SockAddr.sin_addr))) == 0)
			{
				TRACE0("Max clients sessions - 256!!!\n");
				delete pclientSocket;
				continue;
			}

			strcpy(pclientSocket->m_szIP,inet_ntoa(SockAddr.sin_addr));

			pBaseServer->StartCritical();
			pBaseServer->m_ListOfClients.push_back(pclientSocket);
			pBaseServer->EndCritical();

			pclientSocket->Execute();
		}
	}
	SERVER_ACTIVE = FALSE;
	m_bTerminated=TRUE;
	return 0;
}

BOOL CRMSListenSocket::StartServer()
{
    int				nRet;

	m_listenSocket = socket(AF_INET, 
						  SOCK_STREAM, 
						  IPPROTO_TCP);

	LINGER linger = { 1,0 };
	//Fixes Bug in MFC Socket Impl
	setsockopt(m_listenSocket,SOL_SOCKET,SO_LINGER,(LPCTSTR)&linger,sizeof(linger));

	if (m_listenSocket == INVALID_SOCKET)
	{
		TRACE0("Could not create listen socket");
		return FALSE;
	}

	nRet = bind(m_listenSocket, 
				(LPSOCKADDR)&saServer, 
				sizeof(struct sockaddr));
	if (nRet == SOCKET_ERROR)
	{
		TRACE0("bind() error");
		shutdown(m_listenSocket,SD_BOTH);
		closesocket(m_listenSocket);
		m_listenSocket=0;
		return FALSE;
	}

	nRet = listen(m_listenSocket, SOMAXCONN);
	if (nRet == SOCKET_ERROR)
	{
		TRACE0("listen() error");
		shutdown(m_listenSocket,SD_BOTH);
		closesocket(m_listenSocket);
		m_listenSocket=0;
		return FALSE;
	}

	Execute();

	SERVER_ACTIVE = TRUE;

	return TRUE;
}

void CRMSListenSocket::StopServer()
{
	if(SERVER_ACTIVE)
	{
		Terminate();
		SERVER_ACTIVE = FALSE;
	}
}

void CRMSListenSocket::SetPause(BOOL bPause)
{
	m_bPause = bPause;
}
